package com.zbkj.service.service.monitor.impl;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zbkj.common.config.CrmebConfig;
import com.zbkj.common.constants.*;
import com.zbkj.common.exception.AppException;
import com.zbkj.common.model.monitor.ZfbMonitorOrder;
import com.zbkj.common.model.monitor.ZfbMonitorTrafficSetMeal;
import com.zbkj.common.model.order.Order;
import com.zbkj.common.model.order.OrderDetail;
import com.zbkj.common.model.user.User;
import com.zbkj.common.model.user.UserToken;
import com.zbkj.common.response.OrderNoResponse;
import com.zbkj.common.response.wx.WxPayBackResult;
import com.zbkj.common.utils.CrmebDateUtil;
import com.zbkj.common.utils.CrmebUtil;
import com.zbkj.common.utils.RequestUtil;
import com.zbkj.common.utils.WxPayUtil;
import com.zbkj.common.vo.*;
import com.zbkj.service.dao.OrderDao;
import com.zbkj.service.dao.OrderDetailDao;
import com.zbkj.service.dao.monitor.ZfbMonitorOrderMapper;
import com.zbkj.service.service.*;
import com.zbkj.service.service.monitor.IZfbMonitorOpenCloseService;
import com.zbkj.service.service.monitor.IZfbMonitorOrderService;
import com.zbkj.service.service.monitor.IZfbMonitorTrafficSetMealService;
import com.zbkj.service.service.monitor.ZfbMonitorDeviceStatusService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;

/**
 * @ClassName: ZfbMonitorOrderServiceImpl
 * @Description: TODO
 * @Author: fanbing
 * @Date: 2024/11/2 12:07
 * @Version: V1.0
 **/
@Slf4j
@Service
public class ZfbMonitorOrderServiceImpl extends ServiceImpl<ZfbMonitorOrderMapper, ZfbMonitorOrder> implements IZfbMonitorOrderService {

    @Autowired
    private ZfbMonitorOrderMapper zfbMonitorOrderMapper;

    @Autowired
    private UserTokenService userTokenService;
    @Autowired
    private SystemConfigService systemConfigService;

    @Autowired
    private CrmebConfig crmebConfig;

    @Autowired
    private WechatService wechatService;

    @Autowired
    private IZfbMonitorTrafficSetMealService zfbMonitorTrafficSetMealService;

    @Autowired
    private IZfbMonitorOpenCloseService zfbMonitorOpenCloseService;

    @Autowired
    private ZfbMonitorDeviceStatusService zfbMonitorDeviceStatusService;
    @Autowired
    private UserService userService;
    @Autowired
    private OrderService orderService;
    @Autowired
    private OrderDetailService orderDetailService;
    @Autowired
    private OrderStatusService orderStatusService;

    /**
     * 预下单
     *
     * @param order 订单
     * @return 预下单返回对象
     */
    @Override
    public WxPayJsResultVo wxUnifiedorder(ZfbMonitorOrder order) {
        // 获取用户openId
        // 根据订单支付类型来判断获取公众号openId还是小程序openId
        UserToken userToken = new UserToken();
        userToken.setToken("");
        if (order.getPayChannel().equals(PayConstants.PAY_CHANNEL_WECHAT_PUBLIC)) {// 公众号
            userToken = userTokenService.getTokenByUserId(order.getUserId(), UserConstants.USER_TOKEN_TYPE_WECHAT);
        }
        if (order.getPayChannel().equals(PayConstants.PAY_CHANNEL_WECHAT_MINI)
                || order.getPayChannel().equals(PayConstants.PAY_CHANNEL_WECHAT_MINI_VIDEO)) {// 小程序
            userToken = userTokenService.getTokenByUserId(order.getUserId(), UserConstants.USER_TOKEN_TYPE_ROUTINE);
        }

        // 获取appid、mch_id、微信签名key
        String appId = "";
        String mchId = "";
        String signKey = "";
        switch (order.getPayChannel()) {
            case PayConstants.PAY_CHANNEL_WECHAT_PUBLIC:
            case PayConstants.PAY_CHANNEL_H5:// H5使用公众号的信息
            case PayConstants.PAY_CHANNEL_WECHAT_NATIVE:// H5使用公众号的信息
                appId = systemConfigService.getValueByKeyException(WeChatConstants.WECHAT_PUBLIC_APPID);
                mchId = systemConfigService.getValueByKeyException(WeChatConstants.WECHAT_PAY_PUBLIC_MCHID);
                signKey = systemConfigService.getValueByKeyException(WeChatConstants.WECHAT_PAY_PUBLIC_KEY);
                break;
            case PayConstants.PAY_CHANNEL_WECHAT_MINI:
            case PayConstants.PAY_CHANNEL_WECHAT_MINI_VIDEO:
                appId = systemConfigService.getValueByKeyException(WeChatConstants.WECHAT_MINI_APPID);
                mchId = systemConfigService.getValueByKeyException(WeChatConstants.WECHAT_PAY_MINI_MCHID);
                signKey = systemConfigService.getValueByKeyException(WeChatConstants.WECHAT_PAY_MINI_KEY);
                break;
            case PayConstants.PAY_CHANNEL_WECHAT_APP_IOS:
            case PayConstants.PAY_CHANNEL_WECHAT_APP_ANDROID:
                appId = systemConfigService.getValueByKeyException(WeChatConstants.WECHAT_APP_APPID);
                mchId = systemConfigService.getValueByKeyException(WeChatConstants.WECHAT_PAY_APP_MCHID);
                signKey = systemConfigService.getValueByKeyException(WeChatConstants.WECHAT_PAY_APP_KEY);
                break;
        }
        log.info("order===={};;;productId==={}", JSON.toJSONString(order), order.getProductId());
        ZfbMonitorTrafficSetMeal monitorTrafficSetMeal = zfbMonitorTrafficSetMealService.getById(order.getProductId());
        log.info("monitorTrafficSetMeal===={}", JSON.toJSONString(monitorTrafficSetMeal));
        order.setCreateTime(LocalDateTime.now());
        order.setOrderStatus(0);
        order.setPayPrice(monitorTrafficSetMeal.getPrice());
        order.setProductName(monitorTrafficSetMeal.getName());


        // 获取微信预下单对象
        log.info("获取微信预下单对象userToken===={},appId={},mchid={},singkey={}", JSON.toJSONString(userToken), appId, mchId, signKey);
        CreateOrderRequestVo unifiedorderVo = getUnifiedorderVo(order, userToken.getToken(), appId, mchId, signKey);
        order.setOrderNo(unifiedorderVo.getOut_trade_no());
        zfbMonitorOrderMapper.insert(order);


        // 预下单（统一下单）
        CreateOrderResponseVo responseVo = wechatService.payUnifiedorder(unifiedorderVo);
        // 组装前端预下单参数
        Map<String, String> map = new HashMap<>();
        map.put("appId", unifiedorderVo.getAppid());
        map.put("nonceStr", unifiedorderVo.getAppid());
        map.put("package", "prepay_id=".concat(responseVo.getPrepayId()));
        map.put("signType", unifiedorderVo.getSign_type());
        Long currentTimestamp = WxPayUtil.getCurrentTimestamp();
        map.put("timeStamp", Long.toString(currentTimestamp));
        String paySign = WxPayUtil.getSign(map, signKey);
        map.put("paySign", paySign);
        map.put("prepayId", responseVo.getPrepayId());
        map.put("prepayTime", CrmebDateUtil.nowDateTimeStr());
        map.put("outTradeNo", unifiedorderVo.getOut_trade_no());
        if (order.getPayChannel().equals(PayConstants.PAY_CHANNEL_H5)) {
            map.put("mweb_url", responseVo.getMWebUrl());
        }
        if (order.getPayChannel().equals(PayConstants.PAY_CHANNEL_WECHAT_APP_IOS) ||
                order.getPayChannel().equals(PayConstants.PAY_CHANNEL_WECHAT_APP_ANDROID)) {// App
            map.put("partnerid", mchId);
            map.put("package", responseVo.getPrepayId());
            Map<String, Object> appMap = new HashMap<>();
            appMap.put("appid", unifiedorderVo.getAppid());
            appMap.put("partnerid", mchId);
            appMap.put("prepayid", responseVo.getPrepayId());
            appMap.put("package", "Sign=WXPay");
            appMap.put("noncestr", unifiedorderVo.getAppid());
            appMap.put("timestamp", currentTimestamp);
            log.info("================================================app支付签名，map = " + appMap);
            String sign = WxPayUtil.getSignObject(appMap, signKey);
            log.info("================================================app支付签名，sign = " + sign);
            map.put("paySign", sign);
        }
        if (order.getPayChannel().equals(PayConstants.PAY_CHANNEL_WECHAT_NATIVE)) {
            map.put("code_url", responseVo.getCodeUrl());
        }


        WxPayJsResultVo vo = new WxPayJsResultVo();
        vo.setAppId(map.get("appId"));
        vo.setNonceStr(map.get("nonceStr"));
        vo.setPackages(map.get("package"));
        vo.setSignType(map.get("signType"));
        vo.setTimeStamp(map.get("timeStamp"));
        vo.setPaySign(map.get("paySign"));
        if (order.getPayChannel().equals(PayConstants.PAY_CHANNEL_H5)) {
            vo.setMwebUrl(map.get("mweb_url"));
        }
        if (order.getPayChannel().equals(PayConstants.PAY_CHANNEL_WECHAT_APP_IOS) ||
                order.getPayChannel().equals(PayConstants.PAY_CHANNEL_WECHAT_APP_ANDROID)) {// App
            vo.setPartnerid(map.get("partnerid"));
        }
        if (order.getPayChannel().equals(PayConstants.PAY_CHANNEL_WECHAT_NATIVE)) {
            vo.setMwebUrl(map.get("code_url"));
        }
        return vo;
    }


    /**
     * 获取微信预下单对象
     *
     * @return 微信预下单对象
     */
    private CreateOrderRequestVo getUnifiedorderVo(ZfbMonitorOrder order, String openid, String appId, String mchId, String signKey) {
        // 获取域名
        String domain = systemConfigService.getValueByKeyException(SysConfigConstants.CONFIG_KEY_SITE_URL);
        String apiDomain = systemConfigService.getValueByKeyException(SysConfigConstants.CONFIG_KEY_API_URL);

        AttachVo attachVo = new AttachVo(PayConstants.PAY_SERVICE_TYPE_ORDER, order.getUserId());

        CreateOrderRequestVo vo = new CreateOrderRequestVo();
        vo.setAppid(appId);
        vo.setMch_id(mchId);
        vo.setNonce_str(WxPayUtil.getNonceStr());
        vo.setSign_type(PayConstants.WX_PAY_SIGN_TYPE_MD5);
        String siteName = systemConfigService.getValueByKeyException(SysConfigConstants.CONFIG_KEY_SITE_NAME);
        // 因商品名称在微信侧超长更换为网站名称
        vo.setBody(siteName);
        vo.setAttach(JSONObject.toJSONString(attachVo));
        vo.setOut_trade_no(CrmebUtil.getOrderNo(OrderConstants.ORDER_PREFIX_WECHAT));
        // 订单中使用的是BigDecimal,这里要转为Integer类型
        vo.setTotal_fee(order.getPayPrice().multiply(BigDecimal.TEN).multiply(BigDecimal.TEN).intValue());
        vo.setSpbill_create_ip(RequestUtil.getClientIp());
        vo.setNotify_url(apiDomain + PayConstants.WX_PAY_NOTIFY_API_MONITOR_URI);
        switch (order.getPayChannel()) {
            case PayConstants.PAY_CHANNEL_H5:
                vo.setTrade_type(PayConstants.WX_PAY_TRADE_TYPE_H5);
                vo.setOpenid(null);
                break;
            case PayConstants.PAY_CHANNEL_WECHAT_APP_IOS:
            case PayConstants.PAY_CHANNEL_WECHAT_APP_ANDROID:
                vo.setTrade_type(PayConstants.WX_PAY_TRADE_TYPE_APP);
                vo.setOpenid(null);
                break;
            case PayConstants.PAY_CHANNEL_WECHAT_NATIVE:
                vo.setTrade_type(PayConstants.WX_PAY_TRADE_TYPE_NATIVE);
                vo.setProduct_id(order.getOrderNo());
                vo.setOpenid(null);
                break;
            default:
                vo.setTrade_type(PayConstants.WX_PAY_TRADE_TYPE_JS);
                vo.setOpenid(openid);
        }
        CreateOrderH5SceneInfoVo createOrderH5SceneInfoVo = new CreateOrderH5SceneInfoVo(
                new CreateOrderH5SceneInfoDetailVo(
                        domain,
                        systemConfigService.getValueByKeyException(SysConfigConstants.CONFIG_KEY_SITE_NAME)
                )
        );
        vo.setScene_info(JSONObject.toJSONString(createOrderH5SceneInfoVo));

        vo.setTime_start(DateUtil.date().toString(DateConstants.DATE_TIME_FORMAT_NUM));
        DateTime cancelTime = DateUtil.offset(new Date(), DateField.MINUTE, crmebConfig.getOrderCancelTime());
        String cancelStr = cancelTime.toString(DateConstants.DATE_TIME_FORMAT_NUM);
        vo.setTime_expire(cancelStr);
        String sign = WxPayUtil.getSign(vo, signKey);
        vo.setSign(sign);
        return vo;
    }

    @Override
    public List<ZfbMonitorOrder> getOrder(Integer merchantId) {
        LambdaQueryWrapper<ZfbMonitorOrder> lw = new LambdaQueryWrapper<>();
        // lw.eq(ZfbMonitorOrder::getOrderStatus, 1);
        lw.eq(ZfbMonitorOrder::getMerchantId, merchantId);
        lw.orderByDesc(ZfbMonitorOrder::getCreateTime);
        return zfbMonitorOrderMapper.selectList(lw);
    }

    @Override
    public void callBack(WxPayBackResult backResult) {
        ZfbMonitorOrder zfbMonitorOrder = zfbMonitorOrderMapper.selectOne(new LambdaQueryWrapper<ZfbMonitorOrder>().eq(ZfbMonitorOrder::getOrderNo, backResult.getOut_trade_no()));

        if (ObjectUtil.isNull(zfbMonitorOrder)) {
            throw new AppException("订单不存在" + JSON.toJSONString(backResult));
        }
        zfbMonitorOrder.setOrderStatus(1);
        zfbMonitorOrder.setThirdOrderNo(backResult.getTransaction_id());
        zfbMonitorOrderMapper.updateById(zfbMonitorOrder);

        // zfbMonitorOpenCloseService.openAll(zfbMonitorOrder.getMerchantId());


        LocalDateTime newExpireTime = null;
        Integer productId = zfbMonitorOrder.getProductId();
        ZfbMonitorTrafficSetMeal trafficSetMeal = zfbMonitorTrafficSetMealService.getById(productId);
        Map<String, Object> expireTimeByLicense = zfbMonitorDeviceStatusService.getExpireTimeByLicense(zfbMonitorOrder.getLicense());
        if (trafficSetMeal != null && trafficSetMeal.getId() > 0
            && expireTimeByLicense != null) {
            LocalDateTime expireTime = LocalDateTime.now();
            Object obj = expireTimeByLicense.get("expireTime");
            if (obj != null) {
                LocalDateTime lastExpireTime = ((Date)obj).toInstant().atZone(ZoneId.systemDefault())
                        .toLocalDateTime();
                if (expireTime.isBefore(lastExpireTime)) {
                    expireTime = lastExpireTime;
                }
            }

            // 1=月 2=季 3=年
            switch(trafficSetMeal.getType()) {
                case 1:
                    newExpireTime = expireTime.plusMonths(1);
                    break;
                case 2:
                    newExpireTime = expireTime.plusMonths(3);
                    break;
                case 3:
                    newExpireTime = expireTime.plusYears(1);
                    break;
                default:
                    throw new AppException("未知套餐类型");
            }

            if (newExpireTime != null) {
                Map<String, Object> result = new HashMap<>();
                result.put("expireTime", Date.from(newExpireTime.atZone(ZoneId.systemDefault()).toInstant()));
                // 套餐类型（1=免费 2=付费）
                result.put("mealType", 2);
                zfbMonitorDeviceStatusService.processDeviceStatus(zfbMonitorOrder.getLicense(), result, zfbMonitorOrder.getOrderNo());
            }
        }
    }

    @Override
    public void callBack(String orderNo) {
        ZfbMonitorOrder zfbMonitorOrder = getByOrderNo(orderNo);
        Order order = orderService.getByOrderNo(orderNo);

        LocalDateTime newExpireTime = zfbMonitorOrder.getEndTime();
        zfbMonitorOrder.setThirdOrderNo(order.getOutTradeNo());
        zfbMonitorOrder.setPayType(order.getPayType());
        zfbMonitorOrder.setPayChannel(order.getPayChannel());
        // 0-待支付 1-已支付
        if (Objects.equals(order.getPaid(), true)) {
            zfbMonitorOrder.setOrderStatus(1);
        } else {
            zfbMonitorOrder.setOrderStatus(0);
        }
        updateById(zfbMonitorOrder);

        if (newExpireTime != null && order.getPaid()) {
            Map<String, Object> result = new HashMap<>();
            result.put("expireTime", Date.from(newExpireTime.atZone(ZoneId.systemDefault()).toInstant()));
            // 套餐类型（1=免费 2=付费）
            result.put("mealType", 2);
            zfbMonitorDeviceStatusService.processDeviceStatus(zfbMonitorOrder.getLicense(), result, zfbMonitorOrder.getOrderNo());
        }
    }

    @Override
    public ZfbMonitorOrder getByOrderNo(String orderNo) {
        LambdaQueryWrapper<ZfbMonitorOrder> lqw = Wrappers.lambdaQuery();
        lqw.eq(ZfbMonitorOrder::getOrderNo, orderNo);
        return zfbMonitorOrderMapper.selectOne(lqw);
    }

    @Override
    public OrderNoResponse createOrder(ZfbMonitorOrder zfbMonitorOrder) {
        ZfbMonitorTrafficSetMeal monitorTrafficSetMeal = zfbMonitorTrafficSetMealService.getById(zfbMonitorOrder.getProductId());
        zfbMonitorOrder.setPayPrice(monitorTrafficSetMeal.getPrice());
        zfbMonitorOrder.setProductName(monitorTrafficSetMeal.getName());

        User user = userService.getInfo();
        Order order = new Order();
        if (user.getBrandId() != 0) {
            String orderNo = CrmebUtil.getOrderNo(OrderConstants.ORDER_PREFIX_BRAND);
            order.setOrderNo(orderNo);
            order.setLevel(OrderConstants.ORDER_LEVEL_BRAND);
        }else{
            String orderNo = CrmebUtil.getOrderNo(OrderConstants.ORDER_PREFIX_PLATFORM);
            order.setOrderNo(orderNo);
            order.setLevel(OrderConstants.ORDER_LEVEL_PLATFORM);
        }
        // 因为监控流量充值属于平台订单，所以这里不设置商户id
        order.setMerId(0);
        order.setUid(user.getId());
        order.setTotalNum(1);
        order.setProTotalPrice(zfbMonitorOrder.getPayPrice());
        order.setTotalPostage(BigDecimal.ZERO);
        order.setSvipDiscountPrice(BigDecimal.ZERO);
        order.setTotalPrice(zfbMonitorOrder.getPayPrice());
        order.setCouponPrice(BigDecimal.ZERO);
        order.setUseIntegral(0);
        order.setIntegralPrice(BigDecimal.ZERO);
        order.setPayPrice(zfbMonitorOrder.getPayPrice());
        order.setPayPostage(BigDecimal.ZERO);
        order.setPaid(false);
        order.setCancelStatus(OrderConstants.ORDER_CANCEL_STATUS_NORMAL);
        // 监控流量充值订单
        order.setType(OrderConstants.ORDER_TYPE_MONITOR);
        order.setMerCouponPrice(BigDecimal.ZERO);
        order.setPlatCouponPrice(BigDecimal.ZERO);
        order.setIsSvip(user.getIsPaidMember());

        OrderDetail orderDetail = new OrderDetail();
        orderDetail.setOrderNo(order.getOrderNo());
        // 因为监控流量充值属于平台订单，所以这里不设置商户id
        orderDetail.setMerId(0);
        orderDetail.setUid(user.getId());
        orderDetail.setProductId(zfbMonitorOrder.getProductId());
        orderDetail.setProductName(zfbMonitorOrder.getProductName());
        orderDetail.setAttrValueId(zfbMonitorOrder.getProductId());
        orderDetail.setSku("监控流量充值");
        orderDetail.setPrice(zfbMonitorOrder.getPayPrice());
        orderDetail.setPayNum(1);
        orderDetail.setWeight(BigDecimal.ZERO);
        orderDetail.setVolume(BigDecimal.ZERO);
        orderDetail.setProductType(ProductConstants.PRODUCT_TYPE_MONITOR);
        orderDetail.setSubBrokerageType(0);
        orderDetail.setBrokerage(0);
        orderDetail.setBrokerageTwo(0);
        orderDetail.setFreightFee(BigDecimal.ZERO);
        orderDetail.setUseIntegral(0);
        orderDetail.setIntegralPrice(BigDecimal.ZERO);
        orderDetail.setPayPrice(zfbMonitorOrder.getPayPrice());

        orderDetail.setIsSvip(order.getIsSvip());
        orderDetail.setIsPaidMemberProduct(false);
        orderDetail.setVipPrice(BigDecimal.ZERO);

        orderDetail.setMerCouponPrice(BigDecimal.ZERO);
        orderDetail.setPlatCouponPrice(BigDecimal.ZERO);
        orderDetail.setCouponPrice(BigDecimal.ZERO);
        orderDetail.setImage("");

        zfbMonitorOrder.setOrderNo(order.getOrderNo());
        // 0待支付 1已支付
        zfbMonitorOrder.setOrderStatus(0);
        zfbMonitorOrder.setCreateTime(LocalDateTime.now());
        LocalDateTime startTime = LocalDateTime.now();
        LocalDateTime expirtTime = null;
        // 获取设备过期信息
        Map<String, Object> expireInfo = zfbMonitorDeviceStatusService.getExpireTimeByLicense(zfbMonitorOrder.getLicense());
        if (expireInfo != null && expireInfo.get("expireTime") != null) {
            expirtTime = ((Date)expireInfo.get("expireTime")).toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
        }
        if (expirtTime != null && expirtTime.isAfter(startTime)) {
            startTime = expirtTime;
        }
        zfbMonitorOrder.setStartTime(startTime);
        zfbMonitorOrder.setEndTime(getOrderExpireTime(startTime,  monitorTrafficSetMeal));
        save(zfbMonitorOrder);

        orderService.save(order);
        orderDetailService.save(orderDetail);

        // 生成订单日志
        orderStatusService.createLog(order.getOrderNo(), OrderStatusConstants.ORDER_STATUS_CREATE, OrderStatusConstants.ORDER_LOG_MESSAGE_CREATE);

        OrderNoResponse response = new OrderNoResponse();
        response.setOrderNo(order.getOrderNo());
        response.setPayPrice(order.getPayPrice());
        return response;
    }

    private LocalDateTime getOrderExpireTime(LocalDateTime startTime, ZfbMonitorTrafficSetMeal monitorTrafficSetMeal) {
        if (monitorTrafficSetMeal == null) {
            throw new AppException("套餐不存在");
        }

        LocalDateTime endTime = LocalDateTime.now();

        // 1=月 2=季 3=年
        switch (monitorTrafficSetMeal.getType()) {
            case 1:
                endTime = startTime.plusMonths(1);
                break;
            case 2:
                endTime = startTime.plusMonths(3);
                break;
            case 3:
                endTime = startTime.plusYears(1);
                break;
            default:
                break;
        }

        return endTime;
    }
}
